﻿using BnbjoyBackend.Site.ConstantsNS;
using BnbjoyBackend.Site.Extends;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Script.Serialization;

namespace BnbjoyBackend.Site.Security
{
    public class ServiceManager
    {
        private static ServiceManager manager;
        private static object lockObj = new object();

        private ServiceManager() { }

        public static ServiceManager Instance
        {
            get
            {
                if (manager == null)
                {
                    lock (lockObj)
                    {
                        if (manager == null)
                        {
                            manager = new ServiceManager();
                        }
                    }
                }

                return manager; ;
            }
        }

        /// <summary>
        /// Get请求
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="subUrl"></param>
        /// <returns></returns>
        public async Task<string> GetService(string accessToken, string subUrl)
        {
            string url = TokenManager.Instance.ApiUrl.TrimEnd('/') + "/api/";
            url += subUrl;

            var client = new HttpClient();
            client.SetBearerToken(accessToken);
            var result = await client.GetStringAsync(new Uri(url));
            return result;
        }

        /// <summary>
        /// Post请求开放接口
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="subUrl"></param>
        /// <param name="jsonParam"></param>
        /// <returns></returns>
        public async Task<HttpPostResponse> PostOpenService(string accessToken, string subUrl, string jsonParam)
        {
            string url = TokenManager.Instance.ApiUrl.TrimEnd('/') + "/api/";
            url += subUrl;

            HttpClient client = new HttpClient();
            HttpPostResponse postResponse = new HttpPostResponse();

            try
            {
                client.SetBearerToken(accessToken);
                var response = await client.PostAsync(new Uri(url), new StringContent(jsonParam, System.Text.Encoding.UTF8, "application/json"));
                //如果是未授权
                if (response.StatusCode == HttpStatusCode.Unauthorized)
                {
                    //删除原来public access token的session
                    HttpContext.Current.Session[Constants.PublicAccessTokenSession] = null;
                    //重新获取public access token
                    string pat = AuthorizedUserManager.Instance.PublicAccessToken;
                    client.SetBearerToken(accessToken);
                    response = await client.PostAsync(new Uri(url), new StringContent(jsonParam, System.Text.Encoding.UTF8, "application/json"));
                }

                var content = await response.Content.ReadAsStringAsync();
                dynamic resObj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(content);
                postResponse = new HttpPostResponse
                {
                    StatusCode = resObj.StatusCode,
                    Content = resObj.Content
                };
            }
            catch (Exception ex)
            {
                return new HttpPostResponse { StatusCode = HttpStatusCode.InternalServerError, Content = "请求服务异常" };
            }

            return postResponse;
        }

        private HttpPostResponse DoPostSync(string accessToken, string url, string jsonParam, int retryMaxCount)
        {
            HttpPostResponse resultRes;
            int retryCount = 0;

            while (true)
            {
                try
                {
                    HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
                    httpWebRequest.Method = "post";
                    httpWebRequest.ContentType = "application/json";
                    httpWebRequest.Timeout = 15000;
                    var authValue = "Bearer " + accessToken;
                    httpWebRequest.Headers.Add("Authorization", authValue);
                    httpWebRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)";

                    byte[] btBodys = Encoding.UTF8.GetBytes(jsonParam);
                    //httpWebRequest.ContentLength = btBodys.Length;
                    httpWebRequest.GetRequestStream().Write(btBodys, 0, btBodys.Length);

                    using (Stream reqStream = httpWebRequest.GetRequestStream())
                    {
                        reqStream.Write(btBodys, 0, btBodys.Length);
                        reqStream.Close();
                    }

                    string responseData = String.Empty;
                    using (HttpWebResponse response = (HttpWebResponse)httpWebRequest.GetResponse())
                    {
                        using (StreamReader reader = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8))
                        {
                            responseData = reader.ReadToEnd();
                            //responseData结构：{"StatusCode":200,"Content":"{\"userId\":\"911b65522c564dc0a6bf6784019424de\",\"userName\":\"jizhuang\",\"roleName\":\"BA\",\"profileId\":\"fd001b169cd248e89549432df316c98c\",\"permission\":\"*\"}"}
                            resultRes = new HttpPostResponse(HttpStatusCode.OK, responseData);
                            break;
                        }
                    }
                }
                catch (WebException e)
                {
                    using (WebResponse response = e.Response)
                    {
                        HttpWebResponse httpResponse = (HttpWebResponse)response;
                        if (httpResponse.StatusCode == HttpStatusCode.RequestTimeout)
                        {
                            if (retryCount < retryMaxCount)
                            {
                                retryCount++;
                                continue;
                            }
                            else
                            {
                                resultRes = new HttpPostResponse(HttpStatusCode.ServiceUnavailable, "连接服务失败");
                                break;
                            }
                        }
                        else
                        {
                            resultRes = new HttpPostResponse(httpResponse.StatusCode, "网络请求错误");
                            break;
                        }
                    }
                }
                catch (Exception ex)
                {
                    resultRes = new HttpPostResponse(HttpStatusCode.InternalServerError, "服务处理异常");
                    break;
                }
            }

            return resultRes;
        }

        public HttpPostResponse PostServiceSync(string accessToken, string subUrl, string jsonParam, int retryMaxCount = 3)
        {
            string url = TokenManager.Instance.ApiUrl.TrimEnd('/') + "/api/";
            url += subUrl;

            HttpPostResponse postResponse = new HttpPostResponse();
            UrlHelper helper = new UrlHelper(HttpContext.Current.Request.RequestContext);
            string loginUrl = helper.Action("Login", "Account");
            try
            {
                var response = this.DoPostSync(accessToken, url, jsonParam, retryMaxCount);

                //如果是未授权
                if (response.StatusCode == HttpStatusCode.Unauthorized)
                {
                    //refresh token
                    string refreshToken = AuthorizedUserManager.Instance.RefreshToken;
                    if (string.IsNullOrWhiteSpace(refreshToken))
                    {
                        //不存在refresh token，清空相应的无效cookie并返回跳转至用户登录
                        AuthorizedUserManager.Instance.CleanTokenAndSession();
                        return new HttpPostResponse { StatusCode = HttpStatusCode.Redirect, Content = loginUrl };
                    }
                    else
                    {
                        var tokenResponse = TokenManager.Instance.RefreshToken(refreshToken);
                        if (tokenResponse.IsError && tokenResponse.IsError == true)
                        {
                            //无法刷新token，清空相应的无效cookie并返回跳转至用户 登录
                            AuthorizedUserManager.Instance.CleanTokenAndSession();
                            return new HttpPostResponse { StatusCode = HttpStatusCode.Redirect, Content = loginUrl };

                            //HttpContext.Current.Response.RedirectToRoute(
                            //new RouteValueDictionary {
                            //    { "Controller", "Account" },
                            //    { "Action", "Login" }});
                        }
                        else
                        {
                            //重新更新登录态，修改cookie和session，并再次访问服务
                            AuthorizedUserManager.Instance.SetTokenInfo(AuthorizedUserManager.Instance.UserName, tokenResponse.AccessToken, tokenResponse.RefreshToken, false);
                            response = this.DoPostSync(accessToken, url, jsonParam, retryMaxCount);
                        }
                    }
                }
                else if (response.StatusCode == HttpStatusCode.OK)
                {
                    dynamic resObj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(response.Content);
                    postResponse = new HttpPostResponse
                    {
                        StatusCode = resObj.StatusCode,
                        Content = resObj.Content
                    };
                }
                else 
                {
                    postResponse = response;
                }
            }
            catch (Exception ex)
            {
                return new HttpPostResponse { StatusCode = HttpStatusCode.InternalServerError, Content = "请求服务异常" };
            }

            return postResponse;
        }

        /// <summary>
        /// Post请求 (如果token和refresh token均过期，可能会发生跳转)
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="subUrl"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public async Task<HttpPostResponse> PostService(string accessToken, string subUrl, string jsonParam, int retryMaxCount = 3)
        {
            int retryCount = 0;
            string url = TokenManager.Instance.ApiUrl.TrimEnd('/') + "/api/";
            url += subUrl;

            HttpClient client = new HttpClient();
            HttpPostResponse postResponse = new HttpPostResponse();

            UrlHelper helper = new UrlHelper(HttpContext.Current.Request.RequestContext);
            string loginUrl = helper.Action("Login", "Account");

            while (true)
            {
                try
                {
                    client.SetBearerToken(accessToken);
                    var response = await client.PostAsync(new Uri(url), new StringContent(jsonParam, System.Text.Encoding.UTF8, "application/json"));
                    //如果是未授权
                    if (response.StatusCode == HttpStatusCode.Unauthorized)
                    {
                        //refresh token
                        string refreshToken = AuthorizedUserManager.Instance.RefreshToken;
                        if (string.IsNullOrWhiteSpace(refreshToken))
                        {
                            //不存在refresh token，清空相应的无效cookie并返回跳转至用户登录
                            AuthorizedUserManager.Instance.CleanTokenAndSession();
                            postResponse = new HttpPostResponse { StatusCode = HttpStatusCode.Redirect, Content = loginUrl };
                            break;
                        }
                        else
                        {
                            var tokenResponse = TokenManager.Instance.RefreshToken(refreshToken);
                            if (tokenResponse.IsError && tokenResponse.IsError == true)
                            {
                                //无法刷新token，清空相应的无效cookie并返回跳转至用户登录
                                AuthorizedUserManager.Instance.CleanTokenAndSession();
                                postResponse = new HttpPostResponse { StatusCode = HttpStatusCode.Redirect, Content = loginUrl };
                                break;
                            }
                            else
                            {
                                //重新更新登录态，修改cookie和session，并再次访问服务
                                AuthorizedUserManager.Instance.SetTokenInfo(AuthorizedUserManager.Instance.UserName, tokenResponse.AccessToken, tokenResponse.RefreshToken, false);
                                client.SetBearerToken(AuthorizedUserManager.Instance.AccessToken);
                                response = await client.PostAsync(new Uri(url), new StringContent(jsonParam, System.Text.Encoding.UTF8, "application/json"));
                            }
                        }
                    }
                    
                    if (response.StatusCode == HttpStatusCode.RequestTimeout)
                    {
                        if (retryCount < retryMaxCount)
                        {
                            retryCount++;
                            continue;
                        }
                        else
                        {
                            postResponse = new HttpPostResponse(HttpStatusCode.ServiceUnavailable, "连接服务失败");
                            break;
                        }
                    }
                    else if (response.StatusCode == HttpStatusCode.OK)
                    {
                        var content = await response.Content.ReadAsStringAsync();
                        dynamic resObj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(content);
                        postResponse = new HttpPostResponse
                        {
                            StatusCode = resObj.StatusCode,
                            Content = resObj.Content
                        };
                        break;
                    }
                    else if (response.StatusCode == HttpStatusCode.InternalServerError) 
                    {
                        postResponse = new HttpPostResponse(HttpStatusCode.ServiceUnavailable, "请求服务异常");
                        break;
                    }
                }
                catch (Exception ex)
                {
                    return new HttpPostResponse { StatusCode = HttpStatusCode.InternalServerError, Content = "请求服务异常" };
                }
            }

            return postResponse;
        }

    }
}